﻿using System;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
using SailHero.Soft.ESB.Communication.ClientAndServer.Communication.Channels;
using SailHero.Soft.ESB.Communication.ClientAndServer.Communication.Channels.Tcp;
using SailHero.Soft.ESB.Communication.ClientAndServer.Communication.EndPoints.Tcp;

namespace SailHero.Soft.ESB.Communication.Channels.Tcp
{
    /// <summary>
    /// This class is used to listen and accept incoming TCP
    /// connection requests on a TCP port.
    /// </summary>
    internal class TcpConnectionListener : ConnectionListenerBase
    {
        /// <summary>
        /// The endpoint address of the server to listen incoming connections.
        /// </summary>
        private readonly ESBTcpEndPoint _endPoint;

        /// <summary>
        /// Server socket to listen incoming connection requests.
        /// </summary>
        private TcpListener _listenerSocket;

        public log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);


        /// <summary>
        /// The thread to listen socket
        /// </summary>
        private Thread _thread;

        /// <summary>
        /// A flag to control thread's running
        /// </summary>
        private volatile bool _running;

        /// <summary>
        /// Creates a new TcpConnectionListener for given endpoint.
        /// </summary>
        /// <param name="endPoint">The endpoint address of the server to listen incoming connections</param>
        public TcpConnectionListener(ESBTcpEndPoint endPoint)
        {
            _endPoint = endPoint;
        }


        /// <summary>
        /// Starts listening incoming connections.
        /// </summary>
        public override void Start()
        {
            try
            {
                StartSocket();
                _running = true;
                _thread = new Thread(DoListenAsThread);
                _thread.Start();
            }
            catch (Exception ex)
            {
                log.Error("出现异常", ex);
            }
        }

        /// <summary>
        /// Stops listening incoming connections.
        /// </summary>
        public override void Stop()
        {
            _running = false;
            StopSocket();
        }

        /// <summary>
        /// 服务是否正在运行.
        /// </summary>
        public override bool IsRuning()
        {
            return _running;
        }

        /// <summary>
        /// Starts listening socket.
        /// </summary>
        private void StartSocket()
        {
            try
            {
                _listenerSocket = new TcpListener(System.Net.IPAddress.Any, _endPoint.TcpPort);
                _listenerSocket.Server.SetKeepAlive();
                _listenerSocket.Start();
                _listenerSocket.Server.SetKeepAlive();
            }
            catch (Exception ex)
            {
                log.Error("通信出现异常", ex);
            }
        }

        /// <summary>
        /// Stops listening socket.
        /// </summary>
        private void StopSocket()
        {
            try
            {
                _listenerSocket.Stop();
            }
            catch (Exception ex)
            {
                log.Error("通信出现异常", ex);
            }
        }

        /// <summary>
        /// Entrance point of the thread.
        /// This method is used by the thread to listen incoming requests.
        /// </summary>
        private void DoListenAsThread()
        {
            try
            {
                while (_running)
                {
                    AcceptThread();
                }
            }
            catch (Exception ex)
            {

                log.Error("通信出现异常", ex);
            }
        }


        public void AcceptThread()
        {
            try
            {
                Accept();
            }
            catch (Exception ex)
            {
                log.Error("通信出现异常", ex);
            }
        }

        private void Accept()
        {
            try
            {
                var clientSocket = _listenerSocket.AcceptSocket();
                clientSocket.SetKeepAlive();
                if (clientSocket.Connected)
                {
                    TcpCommunicationChannel channel = new TcpCommunicationChannel(clientSocket);
                    OnCommunicationChannelConnected(channel);
                }
            }
            catch (Exception ex)
            {
                log.Error("通信出现异常", ex);
                //Disconnect, wait for a while and connect again.
                StopSocket();
                Thread.Sleep(1000);
                if (!_running)
                {
                    return;
                }

                StartSocket();

            }
        }

    }
}
